package threadpool

import (
	"fmt"
	"runtime"
	"sync"
	"time"
)

type ThreadPool struct {
	isrunning       bool
	corePoolSize    int
	liveNum         int
	busyNum         int
	maximumPoolSize int
	isempty         chan int
	isfull          chan int
	waittask        chan int
	taskqueuesize   int
	taskqueue       Queue
	busymutex       sync.RWMutex
	livemutex       sync.RWMutex
	isrunningmutex  sync.RWMutex
	wg              sync.WaitGroup
}

func GetPool(corepoolsize int, maximumpoolsize int, queuesize int) *ThreadPool {
	return &ThreadPool{
		waittask:        make(chan int),
		taskqueuesize:   queuesize,
		isrunning:       true,
		corePoolSize:    corepoolsize,
		liveNum:         corepoolsize,
		busyNum:         0,
		maximumPoolSize: maximumpoolsize,
		isempty:         make(chan int, queuesize),
		taskqueue:       *GetQueue(),
	}
}

func (p *ThreadPool) Run() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	p.wg.Add(p.corePoolSize)
	p.initworker()
	p.wg.Add(1)
	go p.manager()
	fmt.Println("等待3秒正在启动")
	time.Sleep(time.Duration(3) * time.Second)
	fmt.Println("启动成功")
}

func (p *ThreadPool) WaitFinish() {
	p.wg.Wait()
}

func (p *ThreadPool) manager() {
	fmt.Println("manager正在工作")
	for {
		fmt.Println("2秒之后报告工作")
		time.Sleep(time.Duration(2) * time.Second)
		live := p.getLiveNum()
		queuelen := p.taskqueue.Len()
		fmt.Println(queuelen, live)
		if live < queuelen && live < p.maximumPoolSize {
			fmt.Println("添加工人", queuelen-live, "个工人")
			p.AddWorker(queuelen - live)
		}
		if len(p.isempty) == p.taskqueuesize {
			fmt.Println("manager关闭pool")
			p.isRun(false)
			fmt.Println("通知worker下班")
			p.NotifyWorkerStop()
			fmt.Println("stop")
			p.wg.Done()
			return
		}
	}
}

func (p *ThreadPool) worker(id int) {
	fmt.Println(id, "worker开始工作")
	for {

		if !p.getIsRun() {
			fmt.Println("pool关闭别去排队了", id)
			p.wg.Done()
			return
		}
		if p.taskqueue.IsEmpty() {
			if len(p.isempty) == p.taskqueuesize {
				fmt.Println("worker 很多不排队了", id)
				p.wg.Done()
				return
			}
			fmt.Println("我还是排队吧", id, "----排队人数", len(p.isempty)+1)
			p.isempty <- 1
			p.waittask <- 1

		}
		if !p.getIsRun() {
			fmt.Println(id, "排队解散吧")
			p.wg.Done()
			return
		}
		var t Tasktype = p.getTask()
		p.busymutex.Lock()
		p.busyNum++
		p.busymutex.Unlock()
		fmt.Print(id, ",不用排队了,", "开始工作,我抢到了任务")
		t.Task()
		p.busymutex.Lock()
		p.busyNum--
		p.busymutex.Unlock()

	}
}

func (p *ThreadPool) getTask() Tasktype {
	var task Tasktype
	var err error
	if p.taskqueue.Len() == p.taskqueuesize {
		task, err = p.taskqueue.Pop()
		<-p.isfull
	} else {
		task, err = p.taskqueue.Pop()
	}

	if err != nil {
		return nil
	}
	return task
}

func (p *ThreadPool) AddTask(task Tasktype) {
	if p.taskqueue.Len() == p.taskqueuesize {
		fmt.Println("任务队列满了")
		p.isfull <- 1
	}
	if p.taskqueue.IsEmpty() {
		fmt.Println("任务队列为null,马上添加任务")
		p.taskqueue.Push(task)
		<-p.isempty
		<-p.waittask
		return
	}
	p.taskqueue.Push(task)
	fmt.Println("添加任务成功")
}

func (p *ThreadPool) NotifyWorkerStop() {
	for len(p.isempty) != 0 {
		<-p.isempty
		<-p.waittask
	}
}

func (p *ThreadPool) AddWorker(n int) {
	p.livemutex.Lock()
	p.liveNum++
	p.livemutex.Unlock()
	p.wg.Add(n)
	for i := 0; i < n; i++ {
		go p.worker(i + p.corePoolSize + 1)

	}

}

func (p *ThreadPool) initworker() {
	fmt.Println("正在初始化worker")
	for i := 0; i < p.corePoolSize; i++ {
		go p.worker(i + 1)

	}
}

func (p *ThreadPool) getLiveNum() int {
	p.livemutex.RLock()
	c := p.liveNum
	p.livemutex.RUnlock()
	return c
}

// func (p *ThreadPool) getBusyNum() int {
// 	p.livemutex.RLock()
// 	c := p.busyNum
// 	p.livemutex.RUnlock()
// 	return c
// }

func (p *ThreadPool) isRun(b bool) {
	p.isrunningmutex.Lock()
	p.isrunning = b
	p.isrunningmutex.Unlock()
}

func (p *ThreadPool) getIsRun() bool {
	p.isrunningmutex.RLock()
	defer p.isrunningmutex.RUnlock()
	return p.isrunning
}
